#include <map>
#include <iostream>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#include "ParseSvgToObject.h"

#define MOVE_READ_HEAD	placeinstring += strlen(mytoken);

char* leftTrim(char* in)
{
   char* c;

   c = in;
   while (*c == ' ')
      c++;
   strcpy(in, c);
   return in;
}

char* rightTrim(char* in)
{
   char* c;

   c = in + strlen(in) - 1;
   while (*c == ' ' && c > in)
   {
      *c = '\0';
      c--;
   }
   return in;
}

char* trim(char* in)
{
   leftTrim(in);
   rightTrim(in);
   return in;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

void parseStyleAttr(char* styleAttr, SugElement* element)
{
   char* s;

   s = strstr(styleAttr, ":");

   if (s)
   {
      *s = '\0';
      s++;

      trim(styleAttr);
      trim(s);

      element->addAttribute(styleAttr, s);
   }
}

void parseStyleString(char* styleString, SugElement* element)
{
   char* copy;
   char* copyStart;
   char* tok;
   
   copy = new char[strlen(styleString) + 1];
   copyStart = copy;

   strcpy(copy, styleString);
   
   tok = strtok_r(copy, ";", &copy);
   while (tok)
   {
      parseStyleAttr(tok, element);
      tok = strtok_r(NULL, ";", &copy);
   }
   delete copyStart;
}

void parseAttributes(xmlNodePtr currNode, SugElement* element)
{
   xmlAttrPtr currAttr;
   
   currAttr = currNode->properties;
   while (currAttr)
   {
      element->addAttribute((char*)currAttr->name,
                            (char*)currAttr->children->content);

      if (!xmlStrcmp(currAttr->name, (const xmlChar*) "style"))
          parseStyleString((char*)currAttr->children->content, element);
          
      currAttr = currAttr->next;
   }
}

void parseElements(xmlDocPtr xmlDoc,
                   xmlNodePtr currNode,
                   SugElement* parentNode)
{
   xmlChar* text;
   SugNode* lastSibling;
   SugElement* element;
   
   lastSibling = NULL;
   
   while (currNode)
   {
      element = NULL;
      
      if (!xmlStrcmp(currNode->name, (const xmlChar*) "rect"))
      {
         element = new SugRectElement();
      }
      else if (!xmlStrcmp(currNode->name, (const xmlChar*) "path"))
      {
         element = new SugPathElement();
      }
      else if (!xmlStrcmp(currNode->name, (const xmlChar*) "polygon"))
      {
         element = new SugPolygonElement();
      }
      else if (!xmlStrcmp(currNode->name, (const xmlChar*) "polyline"))
      {
         element = new SugPolylineElement();
      }
      else if (!xmlStrcmp(currNode->name, (const xmlChar*) "use"))
      {
         element = new SugUseElement();
      }
      else if (!xmlStrcmp(currNode->name, (const xmlChar*) "text"))
      {
         text = xmlNodeListGetString(xmlDoc, currNode->xmlChildrenNode, 1);

         if (text)
         {
            element = new SugTextElement();
            ((SugTextElement*)element)->setText((char*)text);
         }
      }
      else if (!xmlStrcmp(currNode->name, (const xmlChar*) "g"))
      {
         element = new SugGroupElement();
         parseElements(xmlDoc, currNode->xmlChildrenNode, element);
      }
      else if (!xmlStrcmp(currNode->name, (const xmlChar*) "symbol"))
      {
         element = new SugSymbolElement();
         parseElements(xmlDoc, currNode->xmlChildrenNode, element);
      }
      else if (!xmlStrcmp(currNode->name, (const xmlChar*) "defs"))
      {
         element = new SugDefsElement();
         parseElements(xmlDoc, currNode->xmlChildrenNode, element);
      }

      if (element)
      {
         element->setParentNode(parentNode);
         element->setPreviousSibling(lastSibling);
         if (lastSibling)
            lastSibling->setNextSibling(element);
         else
            parentNode->setFirstChild(element);
         parentNode->setLastChild(element);
         parentNode->appendChild(element);
         lastSibling = element;
         
         parseAttributes(currNode, element);
      }
      
      currNode = currNode->next;
   }
}

bool parseSvgToObject(char* docname, SugSvgElement* rootElement)
{
   xmlDocPtr doc;
   xmlNodePtr rootNode;
   
   doc = xmlParseFile(docname);

   if (doc == NULL )
   {
      fprintf(stderr,
              "The document was not parsed successfully.\n");
      return false;
   }

   rootNode = xmlDocGetRootElement(doc);

   if (rootNode == NULL)
   {
      fprintf(stderr,
              "The document is empty.\n");
      xmlFreeDoc(doc);
      return false;
   }

   if (xmlStrcmp(rootNode->name, (const xmlChar*) "svg"))
   {
      fprintf(stderr,
              "The document is of the wrong type, root node is not svg.\n");
      xmlFreeDoc(doc);
      return false;
   }

   parseAttributes(rootNode, rootElement);
   parseElements(doc, rootNode->xmlChildrenNode, rootElement);
   
   xmlFreeDoc(doc);
   return true;
}

